﻿(function() {
    var ns = nova.widgets;
    var directions = {
        horizontal: 'horizontal',
        vertical: 'vertical'
    };

    function onTouchMove(obj, xy, direction) {
        if (xy == null) {
            return;
        }
        if (obj._lastPosition == null) {
            obj._lastPosition = xy;
            return;
        }
        obj._vForce = 0;
        obj._hForce = 0;
        if (direction == directions.vertical) {
            obj._vForce = xy.y - obj._lastPosition.y;
        }
        else {
            obj._hForce = xy.x - obj._lastPosition.x;
        }
        var position = obj._$carousel.position();
        if (direction == directions.vertical) {
            obj._$carousel.css("top", (position.top + obj._vForce) + "px");
        } else {
            obj._$carousel.css("left", (position.left + obj._hForce) + "px");
        }
        obj._lastPosition = xy;
    }
    
    function getTargetIndex(obj, direction, sensitivity) {
        var index = obj._currentIndex;
        var prevMiddle = 0;
        var nextMiddle = 0;
        var count = 0;
        
        var position = obj._$carousel.position();
        if (direction == directions.vertical) {
            var newTop = position.top + obj._vForce * sensitivity;
            prevMiddle = -obj._height * obj._currentIndex - obj._height / 2;
            nextMiddle = prevMiddle + obj._height;
            if (newTop <= prevMiddle) {
                index = index - 1;
                if (index < 0) {
                    index = 0;
                }
            }
            if (newTop >= nextMiddle) {
                index = index + 1;
                count = obj._$carousel.children().length;
                if (index >= count) {
                    index = count - 1;
                }
            }
            return index;

        } else {
            var newLeft = position.left + obj._hForce * sensitivity;
            prevMiddle = -obj._width * obj._currentIndex - obj._width / 2;
            nextMiddle = prevMiddle + obj._width;
            if (newLeft <= prevMiddle) {
                index = index + 1;
                count = obj._$carousel.children().length;
                if (index >= count) {
                    index = count - 1;
                }
            }
            if (newLeft >= nextMiddle) {
                index = index - 1;
                if (index < 0) {
                    index = 0;
                }
            }
            return index;
        }
    }

    //=====================================================================================

    ns.Carousel = function(selector) {
        this.selector = selector;
        this.direction = directions.horizontal;
        this.duration = 400;
        this.loop = false;
        this.sensitivity = 10;
        
        this._$carousel = null;
        this._$wrapper = null;
        this._height = 0;
        this._width = 0;
        this._currentIndex = 0;
        this._lastPosition = null;
        this._vForce = 0;
        this._hForce = 0;
        this._isMoving = false;
    };

    ns.Carousel.prototype =
    {
        init: function() {
            var obj = this;
            obj._$carousel = $(obj.selector);
            obj._$wrapper = obj._$carousel.parent();
            obj._$wrapper.addClass("carousel-container");
            obj._$carousel.addClass("carousel");
            obj.refreshSize();

            var dom = obj._$carousel[0];
            var events = nova.touch.eventNames;
            dom.addEventListener(events.touchstart, function (e) {
                e.preventDefault();
                obj._isMoving = false;
                obj._$carousel.stop(true);
                obj._lastPosition = nova.touch.getTouchPosition(e);
            });
            dom.addEventListener(events.touchmove, function (e) {
                if (obj.direction == directions.vertical) {
                    if (e.scrollingVertical) {
                        return;
                    }
                    else {
                        e.scrollingVertical = true;
                    }
                }
                else{
                    if (e.scrollingHorizontal) {
                        return;
                    }
                    else {
                        e.scrollingHorizontal = true;
                    }
                }
                obj._isMoving = true;
                onTouchMove(obj, nova.touch.getTouchPosition(e), obj.direction);
            });
            dom.addEventListener(events.touchend, function () {
                if (obj._isMoving) {
                    var targetIndex = getTargetIndex(obj.direction, obj.sensitivity);
                    obj.gotoIndex(targetIndex);
                }
            });

        },
        getIndex:function() {
            return obj._currentIndex;
        },
        gotoIndex:function(index) {
            var obj = this;
            if (this.direction == directions.vertical) {
                var newTop = -index * obj._height;
                obj._$carousel.animate({
                        top: newTop + "px"
                    }, obj.duration, function() {
                        handleIndexChanged();
                    });
            } else {
                var newLeft = -index * obj._width;
                obj._$carousel.animate({
                        left: newLeft + "px"
                    }, obj.duration, function() {
                        handleIndexChanged();
                    });
            }
            
            function handleIndexChanged() {
                if (index == obj._currentIndex) {
                    return;
                }
                var evt = $.Event("onViewIndexChanged");
                evt.oldIndex = obj._currentIndex;
                evt.newIndex = index;
                obj._currentIndex = index;
                $(obj).trigger(evt);
            }
        },
        hasNext:function() {
            var count = obj._$carousel.children().length;
            return obj._currentIndex < count - 1;
        },
        goNext: function() {
            if (this.hasNext()) {
                this.gotoIndex(obj._currentIndex + 1);
            }
        },
        hasPrevious:function() {
            return obj._currentIndex > 0;
        },
        goPrevious: function() {
            if (this.hasPrevious()) {
                this.gotoIndex(obj._currentIndex - 1);
            }
        },
        refreshSize:function() {
            var obj = this;
            obj._height = obj._$wrapper.innerHeight();
            obj._width = obj._$wrapper.innerWidth();
            if (obj.direction == directions.horizontal) {
                obj._$carousel.width(obj._$carousel.children().length * obj._width);
                obj._$carousel.css("left", -obj._width * obj._currentIndex);
            }
            else{
                obj._$carousel.height(obj._$carousel.children().length * obj._height);
                obj._$carousel.css("top", -obj._height * obj._currentIndex);
            }
            obj._$carousel.children().width(obj._width).height(obj._height).addClass("carousel-view");
        },
        onViewIndexChanged:function(handler) {
            $(this).bind("onViewIndexChanged", function (args) {
                handler && handler(args.oldIndex, args.newIndex);
            });
        }
    };

})();